#define WRITEPROGRESS

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Management.Automation;
using Nivot.PowerShell.WindowsMobile.Rapi2;

namespace Nivot.PowerShell.WindowsMobile
{
    public class CEFolder : CEObject
    {
        internal CEFolder(RemoteDevice device, string path)
            : base(device, path)
        {
        }

        public override string Name
        {
            get
            {
                if (String.IsNullOrEmpty(this.FullPath))
                {
                    // root
                    return @"\";
                }
                return Path.GetFileName(this.FullPath);
            }
        }

        public override DateTime? LastWriteTime
        {
            get
            {
                return null;
            }
        }

        // TRY YIELD RETURN?
        internal Collection<CEFolder> Folders
        {
            get
            {
                var folders = new Collection<CEFolder>();

                try
                {
                    //EnsureCachedFileList(Provider.Force.IsPresent);

                    CeFindAllFilesFlags flags = CeFindAllFilesFlags.FAF_NAME |
                                                CeFindAllFilesFlags.FAF_FOLDERS_ONLY;

                    if (! Provider.Force.IsPresent)
                    {
                        flags |= CeFindAllFilesFlags.FAF_ATTRIB_NO_HIDDEN;
                    }

                    // TODO: support -include -exclude
                    string[] fileNames = Device.GetFiles(this.FullPath, "*", flags);
                    Array.Sort(fileNames);

                    foreach (string fileName in fileNames)
                    {
                        string folderPath = Path.Combine(this.FullPath, fileName);

                        CEFileAttributes attribs = Device.GetFileAttributes(folderPath);
                        if ((attribs & CEFileAttributes.Directory) == CEFileAttributes.Directory)
                        {
                            folders.Add(new CEFolder(Device, folderPath));
                        }
                    }
                }
                catch (RapiException ex)
                {
                    StoreProviderContext.Current.ThrowTerminatingError(
                        new ErrorRecord(ex, "RapiError", ErrorCategory.DeviceError, null));
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(ex, "CEFolder.Folders");
                    throw;
                }
                return folders;
            }
        }

        //internal Collection<CEFile> Files
        internal IEnumerable<CEFile> Files
        {
            get
            {
                //var files = new Collection<CEFile>();
                string[] fileNames = new string[0];
                try
                {
                    //EnsureCachedFileList(Provider.Force.IsPresent);
                    CeFindAllFilesFlags flags = CeFindAllFilesFlags.FAF_NAME;

                    if (!Provider.Force.IsPresent)
                    {
                        flags |= CeFindAllFilesFlags.FAF_ATTRIB_NO_HIDDEN;
                    }

                    // TODO: support -include -exclude                    
                    fileNames = Device.GetFiles(this.FullPath, "*", flags);
                    Array.Sort(fileNames);
                }
                catch (RapiException ex)
                {
                    StoreProviderContext.Current.ThrowTerminatingError(
                        new ErrorRecord(ex, "RapiError", ErrorCategory.DeviceError, null));
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(ex, "CEFolder.Files");
                    throw;
                }

                foreach (string fileName in fileNames)
                {
                    string filePath = Path.Combine(this.FullPath, fileName);

                    CEFileAttributes attribs = Device.GetFileAttributes(filePath);
                    if ((attribs & CEFileAttributes.Directory) == 0)
                    {
                        var file = (CEFile) CEObjectFactory.CreateCEObject(Device, filePath);
                        //files.Add(file);
                        yield return file;
                    }
                }

                //return files;
            }
        }

        internal CEFolder ParentFolder
        {
            get
            {
                if (this.FullPath == @"\")
                {
                    return null;
                }                
                string parentPath = Provider.SessionState.Path.ParseParent(this.FullPath, null);

                return new CEFolder(Device, parentPath);
            }
        }

        private void EnsureCachedFileList(bool forceRefresh)
        {
            //if ((m_fileList == null) || forceRefresh)
            //{                
            //    m_fileList = SafeRapiLib.Instance.GetFileList(Path.Combine(CEFileInformation.FileName, "*"));
            //}
        }

        internal void AddCEFile(CEFile source)
        {
            try
            {
                Device.CopyFile(source.FullPath, Path.Combine(this.FullPath, source.Name), Provider.Force.IsPresent);
            }
            catch (RapiException ex)
            {
                Provider.ThrowTerminatingError(new ErrorRecord(ex, "AddFail",
                    ErrorCategory.WriteError, source.FullPath));
            }
        }

        internal void RemoveCEFile(CEFile target)
        {
            try
            {
                Device.DeleteFile(target.FullPath);
            }
            catch (RapiException ex)
            {
                Provider.ThrowTerminatingError(new ErrorRecord(ex, "RemoveFail",
                    ErrorCategory.WriteError, target.FullPath));
            }
        }

        internal void RemoveCEFolder(CEFolder target)
        {
            try
            {
                if (this.FullPath.Equals(target.FullPath, StringComparison.OrdinalIgnoreCase))
                {
                    var ex = new PSArgumentException("Cannot delete the current directory.");
                    Provider.ThrowTerminatingError(new ErrorRecord(ex, "RemoveFail",
                        ErrorCategory.WriteError, target.FullPath));
                }
                else
                {
                    Device.RemoveDirectory(target.FullPath);
                }
            }
            catch (RapiException ex)
            {
                Provider.ThrowTerminatingError(new ErrorRecord(ex, "RemoveFail",
                    ErrorCategory.WriteError, target.FullPath));
            }
        }

        internal void CreateCEFolder(string fullPath)
        {
            try
            {
                Device.CreateDirectory(fullPath);
            }
            catch (RapiException ex)
            {
                Provider.ThrowTerminatingError(new ErrorRecord(ex, "CreateFail",
                    ErrorCategory.WriteError, fullPath));
            }
        }
    }
}